﻿using Ionic.Zip;
using Microsoft.InformationProtectionAndControl;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;

namespace CloudStorageLight.Core.Web
{
    /// <summary>
    /// FilesControllerのヘルパー
    /// </summary>
    [Authorize]
    public abstract class HelperControllerBase : Controller
    {
        protected virtual BlobUser GetCurrentUser()
        {
            var user = new BlobUser(System.Web.HttpContext.Current.User);
            return user;
        }

        protected virtual string GetUserEncryptedFileProtectedPassword(BlobService svc, BlobUser u)
        {
            var info = svc.GetUserInfo(u);
            return info == null ? null : info.EncryptedFileProtectedPassword;
        }

        protected abstract BlobService CreateBlobService();

        /// <summary>
        /// ZIPでダウンロード
        /// </summary>
        /// <param name="fc"></param>
        /// <returns></returns>
        [AllowAnonymous]
        public virtual async Task<ActionResult> DownloadAsZip(FormCollection fc)
        {
            string tempzip = null;
            try
            {
                using (var svc = CreateBlobService())
                {
                    var pathList = new List<string>();
                    foreach (var key in fc.AllKeys)
                    {
                        if (!key.StartsWith("file")) continue;
                        var path = HttpUtility.UrlDecode(fc[key]);
                        pathList.Add(path);
                    }
                    tempzip = await WebUtil.CreateZipFile(svc, GetCurrentUser(), pathList);
                }

                using (var source = new FileStream(tempzip, FileMode.Open))
                {
                    Response.BufferOutput = false;
                    Response.SetCookie(new HttpCookie("fileDownload", "true") { Path = "/" });
                    Response.ContentType = "application/octet-stream";
                    var strFileName = "downloadfiles.zip";
                    Response.AddHeader("Content-Disposition", "attachment; filename=" + strFileName);
                    await source.CopyToAsync(Response.OutputStream);
                }

                return new EmptyResult();

            }
            finally
            {
                if (tempzip != null) System.IO.File.Delete(tempzip);
            }
        }


        /// <summary>
        /// フォルダリストDropDownList
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<ActionResult> DirectoryDropDownList(string id, string name)
        {
            BlobUser user = GetCurrentUser();

            using (var svc = CreateBlobService())
            {
                try
                {
                    var files = await svc.ListFilesAsync(user, id, 0);
                    var current = (BlobDirectory)await svc.GetBlobItemAsync(user, id);

                    var items = files.OfType<BlobDirectory>().Select(x => new SelectListItem { Text = x.Path, Value = x.Path, Selected = x.Path == id }).ToList();

                    for (var dire = current; dire != null; dire = dire.GetParent())
                    {
                        if (items.Any(x => x.Value == dire.Path)) continue;
                        items.Insert(0, new SelectListItem { Text = dire.Path, Value = dire.Path, Selected = dire.Path == id });
                    }
                    ViewData["DropdownListName"] = name;
                    return PartialView("_DirectoryDropDownList", items);
                }
                catch (Exception ex)
                {
                    svc.EntryLog(user, "Error", this.Request.Url.PathAndQuery, ex.ToString());
                    return Content(ex.Message);
                }

            }

        }

        /// <summary>
        /// ディレクトリ設定
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<ActionResult> ShowBlobDirectorySettings(string id)
        {
            BlobUser user = GetCurrentUser();
            using (var svc = CreateBlobService())
            {
                try
                {
                    if (!await svc.CanControlAsync(user, id)) throw new BlobException(BlobExceptionCode.NotAuthorization);

                    var item = (BlobDirectory)await svc.GetBlobItemAsync(user, id);
                    var vm = new AppBlobDirectoryVM();
                    vm.User = user;
                    vm.Path = item.Path;
                    vm.AccessTokens = item.AccessTokens;
                    vm.BackupMode = item.BackupMode;
                    vm.SearchMode = item.SearchedMode;
                    vm.CaseInsensitive = item.CaseInsensitive;
                    vm.DecryptableFileOnly = item.DecryptableFileOnly;
                    vm.DownloadFromOriginalUrl = item.DownloadFromOriginalUrl;
                    vm.UploadableFileExtension = item.UploadableFileExtension;
                    vm.FilePasscode = item.FilePasscode;
                    vm.MaxHistorySize = item.MaxHistorySize;
                    vm.ProtectedMode = item.ProtectedMode;
                    if (vm.ProtectedMode == null && item.FilePasscode != null) vm.ProtectedMode = "Password";
                    if (vm.ProtectedMode == null && item.RmsTemplateId != null) vm.ProtectedMode = "RMS";
                    vm.UsersRole = item.UsersRole;

                    vm.RmsTemplateId = item.RmsTemplateId;
                    vm.RmsTemplateIdList = new List<SelectListItem>();
                    vm.RmsTemplateIdList.Add(new SelectListItem() { Text = "", Value = null });

                    if (SystemSettings.Instance.UseRMS && svc.CloudAccount.CanUseRMS)
                    {

                        var tempList = ListRmsTemplateList(svc);
                        foreach (var template in tempList)
                        {
                            vm.RmsTemplateIdList.Add(new SelectListItem() { Text = template.Name, Value = template.TemplateId });
                        }
                        var rmsIdvalue = await svc.GetRmsTemplateIdAsync(id);
                        var rmsTemp = tempList.Where(x => x.TemplateId == rmsIdvalue).FirstOrDefault();
                        vm.RmsTemplateIdValue = ViewMessages.MsgCurrentValue + ":" + (rmsTemp == null ? "" : rmsTemp.Name);
                    }


                    vm.SearchModeValue = ViewMessages.MsgCurrentValue + ":" + (await svc.IsSerachedOnAsync(id) ? "ON" : "OFF");
                    vm.BackupModeValue = ViewMessages.MsgCurrentValue + ":" + (await svc.IsBackupOnAsync(id) ? "ON" : "OFF");
                    vm.CaseInsensitiveValue = ViewMessages.MsgCurrentValue + ":" + (await svc.IsCaseInsensitiveAsync(id) ? "ON" : "OFF");

                    vm.DecryptableFileOnlyValue = ViewMessages.MsgCurrentValue + ":" + (await svc.IsDecryptableFileOnlyAsync(id) ? "ON" : "OFF");

                    var uploadableFileExtension = await svc.GetUploadableFileExtensionAsync(id);
                    vm.UploadableFileExtensionValue = ViewMessages.MsgCurrentValue + ":" + uploadableFileExtension;

                    var protectedMode = await svc.GetProtectedModeAsync(id);
                    vm.ProtectedModeValue = ViewMessages.MsgCurrentValue + ":" + protectedMode;

                    vm.ProtectedModeList = new List<SelectListItem>();
                    vm.ProtectedModeList.Add(new SelectListItem() { Text = "", Value = null });
                    vm.ProtectedModeList.Add(new SelectListItem() { Text = ViewMessages.MsgNone, Value = "None" });
                    if (svc.CloudAccount.CanUseAutoPassword)
                    {
                        vm.ProtectedModeList.Add(new SelectListItem() { Text = ViewMessages.MsgPasswordProtected, Value = "Password" });
                        vm.ProtectedModeList.Add(new SelectListItem() { Text = ViewMessages.MsgZipPasswordProtected, Value = "ZipPassword" });
                        if (svc.CloudAccount.CanUseUserPasswordProtect)
                        {
                            vm.ProtectedModeList.Add(new SelectListItem() { Text = ViewMessages.MsgUserPasswordProtected, Value = "UserPassword" });
                            vm.ProtectedModeList.Add(new SelectListItem() { Text = ViewMessages.MsgZipUserPasswordProtected, Value = "ZipUserPassword" });
                        }
                    }
                    if (SystemSettings.Instance.UseRMS && svc.CloudAccount.CanUseRMS) vm.ProtectedModeList.Add(new SelectListItem() { Text = "RMS", Value = "RMS" });

                    vm.MaxHistorySizeValue = ViewMessages.MsgCurrentValue + ":" + (await svc.GetMaxHistorySizeAsync(id)).ToString();
                    return PartialView("_BlobDirectorySettings", vm);
                }
                catch (Exception ex)
                {
                    svc.EntryLog(user, "Error", this.Request.Url.PathAndQuery, ex.ToString());
                    return Content(ex.Message);
                }
            }
        }

        private Collection<Microsoft.InformationProtectionAndControl.TemplateInfo> ListRmsTemplateList(BlobService svc)
        {
            var sym = new SymmetricKeyCredential();
            sym.AppPrincipalId = svc.CloudAccount.RmsServicePrincipal;
            sym.Base64Key = svc.CloudAccount.RmsSymmetricKey;
            sym.BposTenantId = svc.CloudAccount.TenantId;
            var info = new ConnectionInfo(new Uri(svc.CloudAccount.RmsExtranetUrl), new Uri(svc.CloudAccount.RmsIntranetUrl));
            var tempList = RmsUtil.GetTemplateList(info, sym);
            return tempList;
        }
        private bool IsPasswordProtectMode(string protectedMode)
        {
            if (protectedMode == "Password" || protectedMode == "UserPassword") return true;
            if (protectedMode == "ZipPassword" || protectedMode == "ZipUserPassword") return true;
            return false;
        }


        /// <summary>
        /// フォルダ設定を更新する
        /// </summary>
        /// <returns></returns>
        public async Task<ActionResult> UpdateBlobDirectorySettings(string id, AppBlobDirectoryVM vm, FormCollection fc)
        {
            BlobUser user = GetCurrentUser();
            var svc = CreateBlobService();
            try
            {
                if (!await svc.CanControlAsync(user, id)) throw new BlobException(BlobExceptionCode.NotAuthorization);

                var item = (BlobDirectory)await svc.GetBlobItemAsync(user, id);
                item.BackupMode = vm.BackupMode;
                item.SearchedMode = vm.SearchMode;
                item.FilePasscode = vm.FilePasscode;
                item.MaxHistorySize = vm.MaxHistorySize;
                item.CaseInsensitive = vm.CaseInsensitive;
                item.ProtectedMode = vm.ProtectedMode;
                item.RmsTemplateId = vm.RmsTemplateId;
                item.UsersRole = vm.UsersRole;
                item.DecryptableFileOnly = vm.DecryptableFileOnly;
                item.DownloadFromOriginalUrl = vm.DownloadFromOriginalUrl;
                item.UploadableFileExtension = vm.UploadableFileExtension;

                if (!string.IsNullOrEmpty(item.FilePasscode))
                {
                    if (item.FilePasscode.Length <= 5) return Content(ViewMessages.MsgInvalidPassword);
                    if (!item.FilePasscode.Any(x => char.IsNumber(x)) || !item.FilePasscode.Any(x => char.IsLetter(x)))
                    {
                        return Content(ViewMessages.MsgInvalidPassword);
                    }
                }
                else
                {
                    if (IsPasswordProtectMode(item.ProtectedMode))
                    {
                        return Content(ViewMessages.MsgRequiredPasscode);
                    }
                }
                if (item.ProtectedMode == "RMS" && string.IsNullOrEmpty(item.RmsTemplateId))
                {
                    return Content(ViewMessages.MsgRequiredRmsTempalateID);
                }

                if (item.MaxHistorySize < 0)
                {
                    return Content(ViewMessages.MsgMaxHistorySizeInputError);
                }

                item.AccessTokens.Clear();
                int idx = 0;
                while (true)
                {
                    var inuse = "AccessTokens[" + idx.ToString() + "].InUse";
                    var role = "AccessTokens[" + idx.ToString() + "].Role";
                    var read = "AccessTokens[" + idx.ToString() + "].CanRead";
                    var write = "AccessTokens[" + idx.ToString() + "].CanWrite";
                    var modify = "AccessTokens[" + idx.ToString() + "].CanModify";
                    var control = "AccessTokens[" + idx.ToString() + "].CanControl";
                    idx++;

                    if (!fc.AllKeys.Contains(role)) break;

                    if (!string.IsNullOrWhiteSpace(fc[inuse]) && fc[inuse].StartsWith("false")) continue;
                    if (fc[role] == null) continue;
                    if (string.IsNullOrWhiteSpace(fc[role])) continue;

                    var token = new BlobAccessToken(fc[role]);
                    if (!string.IsNullOrWhiteSpace(fc[read]) && fc[read].StartsWith("true")) token.CanRead = true;
                    if (!string.IsNullOrWhiteSpace(fc[write]) && fc[write].StartsWith("true")) token.CanWrite = true;
                    if (!string.IsNullOrWhiteSpace(fc[modify]) && fc[modify].StartsWith("true")) token.CanModify = true;
                    if (!string.IsNullOrWhiteSpace(fc[control]) && fc[control].StartsWith("true")) token.CanControl = true;
                    item.AccessTokens.Add(token);
                }
                await item.SetMetadataAsync();

                svc.EntryLog(user, "UpdateBlobDirectorySettings", id,vm.ToString());

                if (item.AccessTokens.Count > 0)
                {
                    svc.EntryLog(user, "UpdateBlobDirectorySettings", id, string.Join(",", item.AccessTokens.Select(x => x.Token)));
                }

                return Content("");
            }
            catch (Exception ex)
            {
                svc.EntryLog(user, "Error", this.Request.Url.PathAndQuery, ex.ToString());
                return Content(ex.Message);
            }
        }

        public ActionResult ClearCustomAuthInfo(string id)
        {
            BlobUser user = GetCurrentUser();
            using (var svc = CreateBlobService())
            {
                var customAuth = svc.GetCustomAuth(id);
                customAuth.User = "";
                customAuth.Expires = DateTime.MinValue;
                svc.SetCustomAuth(customAuth);
                Response.Cookies[customAuth.Key].Value = "";
            }
            return Content("");
        }
    }
}